import 'dart:io';
import 'dart:typed_data';

import 'package:camera/camera.dart';
import 'package:dio/dio.dart';
import 'package:flutter_image_compress/flutter_image_compress.dart';
import 'package:hygf/http/file_transfer/down_cap.dart';
import 'package:hygf/http/file_transfer/upload_request_option.dart';
import 'package:hygf/http/file_transfer/upload_result.dart';
import 'package:mime/mime.dart';

import 'package:path_provider/path_provider.dart';
import 'package:intl/intl.dart';
import '../../config/ApiConfig.dart';
import '../../util/LoadingUtils.dart';
import '../../util/cache_util.dart';
import '../../util/format_util.dart';
import '../DioClient.dart';
import '../core/ResponseData.dart';

/// DioClient扩展
/// 为DioClient添加文件上传能力
extension UploadCap on DioClient {
  static const String TYPE_SIGN = "sign";
  static const String TYPE_MEDIA = "media";
  static const String TYPE_DOC = "doc";

  /// 上传文件
  ///
  /// [option]上传文件参数
  ///   type：文件类型
  ///   filePath：文件地址
  /// [hideLoading]是否需要隐藏loading框
  ///
  /// 异步方法
  ///
  /// 返回值为[ResponseData]
  ///   [ResponseData.data]为[UploadResult]
  ///
  Future<ResponseData> uploadFile(
      {required FileUploadRequestOption option,bool isAsync = false,
      bool hideLoading = false,bool isMeter = false}) async {
    var flag = await _checkCompressImg(option.filePath,isMeter);
    print("uploadFromMemory>---flag-----------${flag}-");
    if (flag) {
      Uint8List? result = await compressFileWithInSampleSize(File(option.filePath),isMeter);
      String fileName = XFile(option.filePath).name;
      Stream<List<int>> stream = Stream.value(
        List<int>.from(result!),
      );
      var multipartFile = await MultipartFile.fromFile(option.filePath);
      ResponseData response = await _upload(fileName, multipartFile, result.length,
          filePath: option.filePath,isAsync: isAsync, hideLoading: hideLoading);
      return response;
    } else {
      try{
        String fileName = XFile(option.filePath).name;
        var multipartFile = await MultipartFile.fromFile(option.filePath,filename:fileName);
        int contentLength = File(option.filePath).lengthSync();
        ResponseData response = await _upload(fileName, multipartFile, contentLength,
            filePath: option.filePath,isAsync: isAsync, hideLoading: hideLoading);
        return response;
      }on Exception {
        var json = {
          "code": "-1",
          "msg": "上传失败",
          "data": {}
        };
        ResponseData response = ResponseData.fromJson(json);
        response.isok = false;
        return response;
      }
    }
  }

  /// 上传内存文件
  /// 手签的照片很小不需要压缩
  ///
  /// [option]上传文件参数
  ///   type：文件类型
  ///   file：文件自节码
  ///   fileName：非必填字段 如该字段不为空 则使用该文件名 如该字段为空 则使用uuid 传递文件名时 请带后缀 如【image20200704001.jpg】
  ///   suffix：文件后缀
  /// [hideLoading]是否需要隐藏loading框
  ///
  /// 异步方法
  ///
  /// 返回值为[ResponseData]
  ///   [ResponseData.data]为[UploadResult]
  ///
  Future<ResponseData> uploadFromMemory(
      {required MemoryUploadRequestOption option,
        bool isAsync = false,bool hideLoading = false}) async {

    String fileName = "";
    if (option.fileName != null) {
      fileName = option.fileName!;
    } else {
      fileName =
          "${option.type.toString().split(".").last}_${FormatUtil.formatTime(DateTime.now(), format: "yyyyMMddHHmmss")}.${option.suffix}";
    }
    // //压缩图片
    // print("uploadFromMemory>>>uploadFromMemory>>option>>>>${option}");
    // if(_checkHaveImg(fileName)){
    //   try {
    //     var result = await FlutterImageCompress.compressWithList(
    //       option.file,
    //       quality: 60,
    //     );
    //     print("wangqingxu>>>>>uploadFromMemory>>length>>${result?.length}");
    //   } on Exception {
    //     print("压缩异常>---------------");
    //   }
    // }
    print("uploadFromMemory>---------------");
    int contentLength = option.file.lengthInBytes;
    ResponseData response = await _upload(fileName, MultipartFile.fromBytes(option.file), contentLength,
        isAsync: isAsync,hideLoading: hideLoading);
    return response;

  }

  /// 多文件上传
  ///
  /// [files] 上传文件参数列表 可以传[FileUploadRequestOption] or [MemoryUploadRequestOption]
  /// [progressListener] 进度监听方法 方法中的三个参数第一个是返回的[ResponseData] 第二个是当前上传的第几个文件 第三个是总文件数量
  ///
  /// 异步方法
  ///
  /// 返回值[ResponseData]列表
  ///   [ResponseData.data]为[UploadResult]
  ///
  Future<List<ResponseData?>> uploadFiles(List<BaseUploadRequestOption> files,
      {Function(ResponseData? data, int index, int total)? progressListener,
        bool isAsync = false, bool hideLoading = false,bool isMeter = false}) async {
    if (!hideLoading) {
      LoadingUtils.showProgress(0.0);
    }
    List<ResponseData?> responseList = [];
    int i = 0;
    for (var element in files) {
      ResponseData? response;
      if (element is FileUploadRequestOption) {
        response = await uploadFile(option: element, isAsync:isAsync,hideLoading: true);
      } else if (element is MemoryUploadRequestOption) {
        response = await uploadFromMemory(option: element, isAsync:isAsync,hideLoading: true);
      }
      progressListener?.call(response, i, files.length);
      responseList.add(response);
      if (!hideLoading) {
        LoadingUtils.showProgress(i.toDouble() / files.length);
      }
      i++;
    }

    if (!hideLoading) {
      LoadingUtils.dismiss();
    }
    return responseList;
  }

  Future<ResponseData> _upload(String fileName, MultipartFile stream, int contentLength,
      {String filePath = '',bool isAsync = false, bool hideLoading = false}) async {
    if (!hideLoading) {
      LoadingUtils.loading();
    }
    try {
        String uploadUrl = ApiConfig.uploadFile;
        String objectName = fileName;
        var formData = FormData.fromMap({
          'file': stream,
          'type': lookupMimeType(fileName),
          "businessType": "businessType"
        });

        if(isAsync){// 异步上传
          Future(() async {
            var upRes = await put(uploadUrl,
                data: formData,
                options: Options(
                    contentType: "multipart/form-data",
                    headers: {'content-length': contentLength.toString(),},
                    extra: {
                      "hideLoading": true,
                      "hideNetError": true,
                    }));

            // 上传失败，保存图片信息
            if(upRes.statusCode != 200){
              _saveFailImage(fileName,filePath,objectName,uploadUrl);
            }
          });

          if (!hideLoading) {
            LoadingUtils.dismiss();
          }
          ResponseData downRes = ResponseData.fromJson({'data': ""});
          return downRes;
        }else{// 同步上传
          ResponseData upRes = await DioClient().doPost(uploadUrl, data: formData,options: Options(
              contentType: "multipart/form-data",
              headers: {'content-length': contentLength.toString()},
              extra: {"hideLoading": true}));
          LoadingUtils.dismiss();
          if(upRes.code== "0"){
            upRes.isok = true;
            UploadResult entity = UploadResult.fromJson(upRes.data);
            entity.filePath  = filePath;
            upRes.data = entity;
          }else{
            upRes.isok = false;
          }
          return upRes;
        }
    } on Exception {
      ResponseData data = ResponseData.fromJson({'data': ""});
      data.isok = false;
      if (!hideLoading) {
        LoadingUtils.dismiss();
      }
      return data;
    }
  }

  /// 上传失败，保存图片信息
  _saveFailImage(String fileName,String filePath,String objectName,String uploadUrl) async {
    Future(() async {
      String lower = fileName.toLowerCase();
      if(lower.endsWith(".jpg") || lower.endsWith(".png") ||
          lower.endsWith(".jpeg") || lower.endsWith(".bmp")){
        var extPath = await getExternalStorageDirectory();
        // 创建failImg文件夹
        Directory directory = Directory('${extPath?.path}/failImg');
        if (!directory.existsSync()) {
          directory.createSync();
        }

        String name = DateFormat("yyyyMMddHHmmssSSS").format(DateTime.now()) +
            fileName.substring(fileName.lastIndexOf('.'));
        // 将缓存的照片复制到failImg下
        File file = File(filePath);
        String path = '${extPath?.path}/failImg/$name';
        if (file.existsSync()) {
          file.copySync(path);
        }

        var failData = {
          'fileName':name,
          'filePath':path,
          'objectName':objectName,
          'uploadUrl':uploadUrl,
        };

        Map<String, dynamic>? failImage = CacheUtil().getJson('failImage');
        if(failImage == null || failImage.isEmpty){
          failImage = {'list':[]};
        }
        failImage['list']!.add(failData);
        CacheUtil().setJson('failImage',failImage);
      }
    });
  }

  _getFileTypeStr(UploadFileType type) {
    String typeStr = "";
    switch (type) {
      case UploadFileType.signature:
        typeStr = TYPE_SIGN;
        break;
      case UploadFileType.media:
        typeStr = TYPE_MEDIA;
        break;
      case UploadFileType.doc:
        typeStr = TYPE_DOC;
        break;
    }
    return typeStr;
  }

  //检测是否包含图片并且大于100KB(拍照读表为500kb)
  _checkCompressImg(String fileName,bool isMeter) async {
    int size = 1048576;
    try{
      String lowerString = fileName.toLowerCase();
      File file = File(fileName);
      var length = file.lengthSync();
      if (length > size) {
        if (lowerString.endsWith(".jpg")) {
          return true;
        }
        if (lowerString.endsWith(".png")) {
          return true;
        }
        if (lowerString.endsWith(".jpeg")) {
          return true;
        }
        if (lowerString.endsWith(".bmp")) {
          return true;
        }
      }
      return false;
    }on Exception {
      return false;
    }
  }

  //图片并且大于100KB或者500kb,设置inSampleSize压缩(拍照读表为500kb)
  Future<Uint8List?> compressFileWithInSampleSize(File file,bool isMeter) async {
    int size = 1048576;
    int inSampleSize = file.lengthSync()~/size;
    var result = await FlutterImageCompress.compressWithFile(
      file.absolute.path,
      inSampleSize: inSampleSize,
    );
    // print(result?.length);
    return result;
  }
}
